#pragma once

#include <thread>
#include <vector>
#include <queue>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <iostream>

class ThreadPool {
public:
    template<class F, class... Args>
    // &&右值引用
    void enqueue(F &&f, Args &&...args);

    ThreadPool(const ThreadPool &) = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;

    static ThreadPool& getInstance();
private:
    ThreadPool(size_t num_threads);
    ~ThreadPool();
private:    
    std::vector<std::thread> threads_;
    std::queue<std::function<void()>> tasks_;
    std::mutex mtx_;
    std::condition_variable condition_;
    bool stop_ = false;
};

template<class F, class... Args>
void ThreadPool::enqueue(F &&f, Args &&...args) {
    // std::forward 完美转发
    std::function<void()> task = std::bind(std::forward<F>(f), std::forward<Args>(args)...);

    { //互斥锁作用域
        std::unique_lock<std::mutex> lock(mtx_);
        // 如果线程池已停止，抛出异常
        if (stop_) {
            throw std::runtime_error("enqueue on stopped ThreadPool");
        }
        // 将任务添加到任务队列中
        tasks_.emplace(std::move(task));
    }
    // 通知一个线程执行任务
    condition_.notify_one();
}
